package cn.git.agent;

import cn.git.agent.enhance.EnhancedContext;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.scaffold.TypeValidation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;
import java.util.List;

import static net.bytebuddy.matcher.ElementMatchers.nameContains;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;

/**
 * @description: 仿照skywalking编写的探针入口
 * @program: bank-credit-sy
 * @author: lixuchun
 * @create: 2024-12-23
 */
public class CustomSkyWalkingAgent {

    // 插件查找器
    private static PluginFinder pluginFinder;

    /**
     * premain方法,main方法执行之前进行调用，插桩代码入口
     * @param args 标识外部传递参数
     * @param instrumentation 插桩对象
     */
    public static void premain(String args, Instrumentation instrumentation) {
        // 创建AgentBuilder对象, 用于构建动态类
        // 默认开启类型验证,
        ByteBuddy byteBuddy = new ByteBuddy().with(TypeValidation.of(true));
        AgentBuilder builder = new AgentBuilder.Default(byteBuddy);

        try {
            pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        // 忽略拦截的包
        builder.ignore(
                nameStartsWith("net.bytebuddy.")
                        .or(nameStartsWith("org.slf4j."))
                        .or(nameStartsWith("org.groovy."))
                        .or(nameContains("javassist"))
                        .or(nameContains(".asm."))
                        .or(nameContains(".reflectasm."))
                        .or(nameStartsWith("sun.reflect"))
                        .or(ElementMatchers.isSynthetic()));

        builder.type(pluginFinder.buildTypeMatch())
                .transform(new Transformer())
                        .installOn(instrumentation);

        // 安装
        builder.installOn(instrumentation);
    }

    /**
     * 方法拦截器，拼接对应类拦截后的方法拦截条件拼接
     */
    private static class Transformer implements AgentBuilder.Transformer {
        /**
         * 拦截方法
         * 正常返回   DynamicType.Builder.MethodDefinition.ReceiverTypeDefinition
         *          ReceiverTypeDefinition 继承 ReceiverTypeDefinition<U> extends MethodDefinition
         *          MethodDefinition 继承 MethodDefinition<S> extends Builder
         *          所以返回的 Builder 类型即可
         * @param builder
         * @param typeDescription
         *          可以获取拦截类名 this.getClass().getName() eg: cn.git.agent.service.impl.UserInfoServiceImpl
         *          可以获取增强插件 TypeName eg: com.mysql.jdbc.PreparedStatement
         *
         * @param classLoader
         * @param javaModule
         * @return
         */
        @Override
        public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                                                TypeDescription typeDescription,
                                                ClassLoader classLoader,
                                                JavaModule javaModule) {
            System.out.println("Transformer方法加载 ： typeDescription.getActualName: " + typeDescription.getActualName());
            System.out.println("Transformer方法加载 ： typeDescription.getTypeName: " + typeDescription.getTypeName());
            // 获取插件列表
            List<AbstractClassEnhancePluginDefine> pluginDefineList = pluginFinder.find(typeDescription);
            if (pluginDefineList.size() > 0) {
                // 创建动态类
                DynamicType.Builder<?> newBuilder = builder;
                // 创建EnhancedContext对象
                EnhancedContext enhancedContext = new EnhancedContext();
                for (AbstractClassEnhancePluginDefine pluginDefine : pluginDefineList) {
                    DynamicType.Builder<?> possiableBuilder = pluginDefine.define(typeDescription, newBuilder, classLoader, enhancedContext);
                    if (possiableBuilder != null) {
                        newBuilder = possiableBuilder;
                    }
                }

                // 打印增强信息
                if (enhancedContext.isEnhanced()) {
                    System.out.println("使用" + pluginDefineList.get(0).getClass().getName() + "增强" + typeDescription.getActualName() + "成功");
                }
                return newBuilder;
            }
            return builder;
        }
    }

}
